from xml.dom import minidom
import pyfo

class Resource:
    href = None

class LinkType:
    _node_name = 'Link'
    _attrib_map = {'Link':'name'}    

    def __init__(self, name=None, id=None):
        
        self.name = name
        self.id = id

    def serialize(self):
        schema_attr = {"xmlns":"http://cadac.sdsc.edu/schema",
                       "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
                       "xsi:schemaLocation":"http://cadac.sdsc.edu/schema http://cadac.sdsc.edu/schema/v01/simcat.xsd"}

        if '_attr' in self.__dict__:
            schema_attr.update(self._attr)
        t = self.to_tuple()
        xml = pyfo.pyfo(t, pretty=True, prolog=True, encoding='utf-8')

        return xml

    def toxml(self):
        return self.serialize()

    def __unicode__(self):
        return self.serialize()

    def __str__(self):
        return self.serialize()

    def to_tuple(self):

        atts = {}
        if self.id:
            atts['id'] = self.id
        
        if atts:
            return (self._node_name, self.name, atts)
        else:
            return (self._node_name, self.name)

    def read(self, xml_str):
        xmldoc = minidom.parseString(xml_str)
        node = xmldoc.getElementsByTagName(self._node_name)[0]
        self.name = node.childNodes[0].data
        id = node.getAttribute('id')
        if id:
            self.id = id

class Reference:
    _node_name = 'Reference'
    _attrib_map = {'Reference':'title'}    

    def __init__(self, title=None, bibcode=None,
                 url=None):
        
        self.title = title
        self.bibcode = bibcode
        self.url = url

    def serialize(self):
        schema_attr = {"xmlns":"http://cadac.sdsc.edu/schema",
                       "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
                       "xsi:schemaLocation":"http://cadac.sdsc.edu/schema http://cadac.sdsc.edu/schema/v01/simcat.xsd"}

        if '_attr' in self.__dict__:
            schema_attr.update(self._attr)
        t = self.to_tuple()
        xml = pyfo.pyfo(t, pretty=True, prolog=True, encoding='utf-8')

        return xml

    def toxml(self):
        return self.serialize()

    def __unicode__(self):
        return self.serialize()

    def __str__(self):
        return self.serialize()

    def to_tuple(self):

        atts = {}
        if self.bibcode:
            atts['bibcode'] = self.bibcode
        if self.url:
            atts['href'] = self.url
        
        if atts:
            return ('Reference', self.title, atts)
        else:
            return ('Reference', self.title)

    def read(self, xml_str):
        xmldoc = minidom.parseString(xml_str)
        node = xmldoc.getElementsByTagName('Reference')[0]
        self.title = node.childNodes[0].data
        url = node.getAttribute('href')
        if url:
            self.url = url
        bibcode = node.getAttribute('bibcode')
        if bibcode:
            self.bibcode = bibcode

class XMLBase:
    schema = None
    _attr = None
    _attrib_map = {}
    _attrib_class_map = {}
    _list_map = {}
    _has_references = False

    def to_tuple(self):
        self._build_tuple()
        return (self._node_name, self._elements)

    def _build_tuple(self):
        self._elements = []

        for k in self._attrib_map:
            try:
                val = eval("self.%s" % (self._attrib_map[k]))
                self._elements.append((k, val))
            except:
                pass

        if self._list_map:
            for node_name in self._list_map:
                out_nodes = []
                items = eval('self.%s' % (self._list_map[node_name]["attribute"]))
                
                for item in items:
                    out_nodes.append(item.to_tuple())
                out_nodes = (node_name+'List', out_nodes)
                self._elements.append(out_nodes)

        for node_name in self._attrib_class_map:
            if eval('self.%s'  % (self._attrib_class_map[node_name]["attribute"])):
                t = eval('self.%s.to_tuple()' % (self._attrib_class_map[node_name]["attribute"]))
                self._elements.append(t)

    def serialize(self):
        schema_attr = {"xmlns":"http://cadac.sdsc.edu/schema",
                       "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance",
                       "xsi:schemaLocation":"http://cadac.sdsc.edu/schema http://cadac.sdsc.edu/schema/v01/simcat.xsd"}

        if '_attr' in self.__dict__:
            schema_attr.update(self._attr)
        t = self.to_tuple()
        xml = pyfo.pyfo(t, pretty=True, prolog=True, encoding='utf-8')

        return xml

    def toxml(self):
        return self.serialize()

    def __unicode__(self):
        return self.serialize()

    def __str__(self):
        return self.serialize()

    def write(self, filename):
        fout = open(filename, 'w')
        fout.write(unicode(self))
        fout.close()

    def deserialize(self, xml_string):
        self.read(xml_string)

    def read(self, xml_string):
        self._xmldoc = minidom.parseString(xml_string)
        new_dict = {}
        for k in self._attrib_map:
            nodes = self._xmldoc.getElementsByTagName(k)
            if nodes:
                data = nodes[0].childNodes[0].data
                new_dict[self._attrib_map[k]] = data
        for k in self._attrib_class_map:
            nodes = self._xmldoc.getElementsByTagName(k)
            if nodes:
                new_obj = self._attrib_class_map[k]['class']()
                new_obj.read(nodes[0].toxml())
                new_dict[self._attrib_class_map[k]['attribute']] = new_obj
        self.__dict__.update(new_dict)
        if self._list_map:
            self._read_lists()

    def _read_lists(self):
        root_node = self._xmldoc.documentElement
        for list_class in self._list_map:

            list_name = list_class + 'List'

            list_nodes = self._xmldoc.getElementsByTagName(list_name)

            for list_node in list_nodes:
                if list_node.parentNode == root_node:
                    class_nodes = list_node.getElementsByTagName(list_class)

                    for class_node in class_nodes:
                        xmlstr = class_node.toxml()
                        new_class = self._list_map[list_class]['class']()
                        new_class.read(xmlstr)
                        eval('self.%s.append(new_class)' %
                             (self._list_map[list_class]['attribute']))
